﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.LinearAlgebra;
using BasePlatformNet;
using System.Threading;

namespace L9SubSet
{
    public partial class Form_ConvertColor : Form 
    {
        private BaseCoreNet baseCoreNet;
        private int subIndex;
        private int portIndex;
        private int miniIndex;

        private Dictionary<string, string[]> ColorTable;
        private Dictionary<string, string[]> ColorGamut;

        private double[] rgbResult;
        private bool Caculated;
        private int cvtMode = 0; // 0-不转换 1-色温转换 2-色域转换

        public Form_ConvertColor(BaseCoreNet b, int sub, int port, int mini)
        {
            InitializeComponent();
            GenerateColorTable();

            this.baseCoreNet = b;
            this.subIndex = sub;
            this.portIndex = port;
            this.miniIndex = mini;

            initEnvironment();
        }

        // 生成色温到色坐标映射表
        private void GenerateColorTable()
        {
            
            string colortablePath = "conf/colortable.txt";
            string colorgamutPath = "conf/colorgamut.txt";
            ColorTable = new Dictionary<string, string[]>();
            ColorGamut = new Dictionary<string, string[]>();
            try
            {
                StreamReader sr = new StreamReader(colortablePath,Encoding.Default);
                string line;
                while ((line = sr.ReadLine()) != null)
                {
                    // 检查文件每行数据是否合法
                    string[] parts = line.Split(new char[]{'+'});
                    if (parts.Length != 3) continue;
                    int ColorTemp = -1;
                    float ColorCx = -1f;
                    float ColorCy = -1f;
                    int.TryParse(parts[0], out ColorTemp);
                    float.TryParse(parts[1], out ColorCx);
                    float.TryParse(parts[2], out ColorCy);
                    if (ColorTemp < 0 || ColorCx < 0 || ColorCy < 0)
                    {
                        continue;
                    }
                    else
                    {
                        ColorTable.Add(parts[0], parts);
                    }
                }

                sr.Close();

                sr = new StreamReader(colorgamutPath, Encoding.Default);
                while ((line = sr.ReadLine()) != null)
                {
                    string[] parts = line.Split(new char[] { '+' });
                    if (parts.Length != 9) continue;
                    double check = -1;  
                    for (int i = 0; i < 8; i++)
                    {
                        double.TryParse(parts[i + 1], out check);
                        if (check < 0)
                        {
                            break;
                        }
                    }
                    if (check < 0)
                    {
                        continue;
                    }
                    else
                    {
                        ColorGamut.Add(parts[0], parts);
                    }
                }
            }
            catch (FileNotFoundException e)
            {
                MessageBox.Show("读取配置文件错误，无法使用预设");
            }
            catch (Exception e)
            {
                MessageBox.Show("错误");
            }


        }

        private void initEnvironment()
        {
            // 手动指定色坐标功能不开放
            rbCoordinate.Enabled = false;

            //初始化RGB调整值
            rgbResult = new double[3] { 1, 1, 1 };

            //初始化调整值计算标记
            Caculated = false;
            
            // 向色温下拉菜单填充色温
            rbTempareture.Checked = true;
            cbTargetTempareture.Items.Clear();
            foreach (string temp in ColorTable.Keys)
            {
                string temptext = String.Format("{0}K", temp);
                cbTargetTempareture.Items.Add(temptext);
            }
            // 如果没有能填充的色温则禁用色温下拉菜单
            if (cbTargetTempareture.Items.Count == 0)
            {
                cbTargetTempareture.Items.Add("------");
                rbTempareture.Checked = false;
                rbCoordinate.Checked = true;
                rbTempareture.Enabled = false;
            }

             // 向色域下拉菜单填充色域
            cbDefaultGaumt.Items.Add("Customized");
            foreach (string temp in ColorGamut.Keys)
            {
                cbDefaultGaumt.Items.Add(temp);
            }
            cbTargetTempareture.SelectedIndex = 0;
            if (cbDefaultGaumt.Items.Count > 1)
            {
                cbDefaultGaumt.SelectedIndex = 1;
            }
            else
            {
                cbDefaultGaumt.SelectedIndex = 0;
            }
        }

        private void rbTempareture_CheckedChanged(object sender, EventArgs e)
        {
            cbTargetTempareture.Enabled = rbTempareture.Checked;
        }

        private void rbCoordinate_CheckedChanged(object sender, EventArgs e)
        {
            lblTargetCx.Enabled = rbCoordinate.Checked;
            lblTargetCy.Enabled = rbCoordinate.Checked;
            tbTargetCx.Enabled = rbCoordinate.Checked;
            tbTargetCy.Enabled = rbCoordinate.Checked;
        }


        private void cbTargetTempareture_SelectedIndexChanged(object sender, EventArgs e)
        {
            string valstr = cbTargetTempareture.Text.Substring(0, cbTargetTempareture.Text.Length - 1);
            if (!ColorTable.ContainsKey(valstr))
            {
                MessageBox.Show("色温值不正确");
                cbTargetTempareture.SelectedIndex = 0;
            }
            else
            {
                tbTargetCx.Text = ColorTable[valstr][1];
                tbTargetCy.Text = ColorTable[valstr][2];
            }
        }
        /// <summary>
        /// 输入RGBW和目标通道参数，返回RGB调整值
        /// </summary>
        /// <param name="rgbArray">按照RGB的顺序给出色坐标和亮度</param>
        /// <param name="wArray">给出的W色坐标和亮度</param>
        /// <param name="tArray">给出目标W色坐标和亮度</param>
        /// <returns></returns>
        public double[] getRGBPrefix(double[] rgbArray, double[] wArray)
        {
            try
            {
                Matrix<double> rgbMat = Matrix<double>.Build.Dense(3, 3);

                Matrix<double> wMat = Matrix<double>.Build.Dense(3, 1);

                rgbMat[0, 0] = rgbArray[2] * rgbArray[0] / rgbArray[1];
                rgbMat[1, 0] = rgbArray[2];
                rgbMat[2, 0] = rgbArray[2] * (1 - rgbArray[0] - rgbArray[1]) / rgbArray[1];
                rgbMat[0, 1] = rgbArray[5] * rgbArray[3] / rgbArray[4];
                rgbMat[1, 1] = rgbArray[5];
                rgbMat[2, 1] = rgbArray[5] * (1 - rgbArray[3] - rgbArray[4]) / rgbArray[4];
                rgbMat[0, 2] = rgbArray[8] * rgbArray[6] / rgbArray[7];
                rgbMat[1, 2] = rgbArray[8];
                rgbMat[2, 2] = rgbArray[8] * (1 - rgbArray[6] - rgbArray[7]) / rgbArray[7];

                wMat[0, 0] = wArray[2] * wArray[0] / wArray[1];
                wMat[1, 0] = wArray[2];
                wMat[2, 0] = wArray[2] * (1 - wArray[0] - wArray[1]) / wArray[1];


                Matrix<double> resultMat = rgbMat.Solve(wMat);

                return new double[3] { resultMat[0, 0], resultMat[1, 0], resultMat[2, 0] };
            }
            catch (Exception e)
            {
                return new double[3] { -1, -1, -1 };
            }
            
        }

        private void btnAccept_Click(object sender, EventArgs e)
        {
            // 收集必要数据
            double rcx, rcy, gcx, gcy, bcx, bcy, wcx, wcy, tcx, tcy;
            int rY, bY, gY, wY, tY;

            // rgbw的色坐标值
            rcx = rcy = gcx = gcy = bcx = bcy = wcx = wcy = tcx = tcy = -1d; //初始化为负数
            double.TryParse(tbRedCx.Text, out rcx);
            double.TryParse(tbRedCy.Text, out rcy);
            double.TryParse(tbGreenCx.Text, out gcx);
            double.TryParse(tbGreenCy.Text, out gcy);
            double.TryParse(tbBlueCx.Text, out bcx);
            double.TryParse(tbBlueCy.Text, out bcy);
            double.TryParse(tbWhiteCx.Text, out wcx);
            double.TryParse(tbWhiteCy.Text, out wcy);
            double.TryParse(tbTargetCx.Text, out tcx);
            double.TryParse(tbTargetCy.Text, out tcy);

            if (rcx < 0 || rcx > 1 || gcx < 0 || gcx > 1 || bcx < 0 || bcx > 1 || wcx < 0 || wcx > 1 || tcx < 0 || tcx > 1
                || rcy < 0 || rcy > 1 || gcy < 0 || gcy > 1 || bcy < 0 || bcy > 1 || wcy < 0 || wcy > 1 || tcy < 0 || tcy > 1)
            {
                MessageBox.Show("色坐标数值错误, 取值范围应为[0,1]");
                return;
            }

            // rgbw色度值
            rY = gY = bY = tY = -1;
            int.TryParse(tbRedL.Text, out rY);
            int.TryParse(tbGreenL.Text, out gY);
            int.TryParse(tbBlueL.Text, out bY);
            int.TryParse(tbWhiteL.Text, out wY);
            tY = (int)(wY * 0.8);
            if (rY <= 0 || gY <= 0 || bY <= 0 || wY <= 0)
            {
                MessageBox.Show("亮度数值错误，应大于0");
                return;
            }

            // RGB坐标和亮度
            double[] rgbArray = new double[9];
            rgbArray[0] = rcx;
            rgbArray[1] = rcy;
            rgbArray[2] = rY;
            rgbArray[3] = gcx;
            rgbArray[4] = gcy;
            rgbArray[5] = gY;
            rgbArray[6] = bcx;
            rgbArray[7] = bcy;
            rgbArray[8] = bY;

            // W坐标和亮度
            double[] wArray = new double[3];
            wArray[0] = wcx;
            wArray[1] = wcy;
            wArray[2] = wY;

            // 目标坐标和亮度
            double[] tArray = new double[3];
            tArray[0] = tcx;
            tArray[1] = tcy;
            tArray[2] = tY;

            // 生成目标RGB调整值
            double[] target_result = getRGBPrefix(rgbArray, tArray);
            if (target_result[0] < 0 || target_result[1] < 0 || target_result[2] < 0)
            {
                MessageBox.Show("计算失败，请重新检查目标色温");
                lblResultRed.Text = "R:Err";
                lblResultGreen.Text = "G:Err";
                lblResultBlue.Text = "B:Err";
                Caculated = false;

                return;
            }
            else
            {
                rgbResult = maximizeRGBBrightness(target_result);

                if (0 < rgbResult[0] || 0 < rgbResult[1] || 0 < rgbResult[2])
                {
                    MessageBox.Show("计算失败，请重新检查目标色温");
                    lblResultRed.Text = "R:Err";
                    lblResultGreen.Text = "G:Err";
                    lblResultBlue.Text = "B:Err";
                    Caculated = false;
                }
                else
                {
                    //将计算出的调整值显示在界面
                    lblResultRed.Text = String.Format("R:{0:0.00}%", rgbResult[0] * 100);
                    lblResultGreen.Text = String.Format("G:{0:0.00}%", rgbResult[1] * 100);
                    lblResultBlue.Text = String.Format("B:{0:0.00}%", rgbResult[2] * 100);
                    Caculated = true;
                }
            }

            if(Caculated)
            {
                
            }

        }

        private void WriteBrightness(double[] rgbBrightness)
        {
            if (rgbBrightness.Length != 3)
            {
                MessageBox.Show("色温参数不正确");

                return;
            }

            UInt16 ResR = (UInt16)(rgbBrightness[0] * 65535 + 0.5);
            UInt16 ResG = (UInt16)(rgbBrightness[1] * 65535 + 0.5);
            UInt16 ResB = (UInt16)(rgbBrightness[2] * 65535 + 0.5);
        }

        private void WriteGamut(double[] rgbGanut)
        { 
            
        }

        private double[] maximizeRGBBrightness(double[] rgbBrightness)
        {
            if (rgbBrightness.Length != 3)
            {
                return new double[3] { -1, -1, -1 };
            }
            double kr, kg, kb;
            kr = rgbBrightness[0];
            kg = rgbBrightness[1];
            kb = rgbBrightness[2];

            double tr, tg, tb;
            // 假设红色为最高
            tr = 1;
            tg = kg / kr;
            tb = kb / kr;

            if (tg < 1 && tb < 1)
            {
                return new double[3] { tr, tg, tb };
            }

            // 假设绿色为最高
            tg = 1;
            tr = kr / kg;
            tb = kb / kg;

            if (tr < 1 && tb < 1)
            {
                return new double[3] { tr, tg, tb }; 
            }

            // 假设蓝色为最高
            tb = 1;
            tr = kr / kb;
            tg = kg / kb;

            if (tr < 1 && tg < 1)
            {
                return new double[3] { tr, tg, tb };
            }

            return new double[3] { -1, -1, -1 };
        }

        private int[] getRGBBrightness(double[] rgbArray, double[] wArray, double[] rgbPrefixArray)
        {
            Matrix<double> CalMat = Matrix<double>.Build.Dense(3, 3);

            Matrix<double> TargetMat = Matrix<double>.Build.Dense(3, 1);

            CalMat[0, 0] = rgbPrefixArray[0] * rgbArray[0] / rgbArray[1];
            CalMat[1, 0] = rgbPrefixArray[0];
            CalMat[2, 0] = rgbPrefixArray[0] * (1 - rgbArray[0] - rgbArray[1]) / rgbArray[1];
            CalMat[0, 1] = rgbPrefixArray[1] * rgbArray[3] / rgbArray[4];
            CalMat[1, 1] = rgbPrefixArray[1];
            CalMat[2, 1] = rgbPrefixArray[1] * (1 - rgbArray[3] - rgbArray[4]) / rgbArray[4];
            CalMat[0, 2] = rgbPrefixArray[2] * rgbArray[6] / rgbArray[7];
            CalMat[1, 2] = rgbPrefixArray[2];
            CalMat[2, 2] = rgbPrefixArray[2] * (1 - rgbArray[6] - rgbArray[7]) / rgbArray[7];

            TargetMat[0, 0] = wArray[2] * wArray[0] / wArray[1];
            TargetMat[1, 0] = wArray[2];
            TargetMat[2, 0] = wArray[2] * (1 - wArray[0] - wArray[1]) / wArray[1];

            Matrix<double> resultMat = CalMat.Solve(TargetMat);

            int[] result = new int[3];
            result[0] = (int)Math.Round(resultMat[0, 0]);
            result[1] = (int)Math.Round(resultMat[1, 0]);
            result[2] = (int)Math.Round(resultMat[2, 0]);

            return result;
        }

        private double[] getColorGamut(double[] rgbArray, double[] rgbTargetArray)
        {
            Matrix<double> rgbMat = Matrix<double>.Build.Dense(3, 3);

            Matrix<double> rgbTargetMat = Matrix<double>.Build.Dense(3, 3);

            rgbMat[0, 0] = rgbArray[2] * rgbArray[0] / rgbArray[1];
            rgbMat[1, 0] = rgbArray[2];
            rgbMat[2, 0] = rgbArray[2] * (1 - rgbArray[0] - rgbArray[1]) / rgbArray[1];
            rgbMat[0, 1] = rgbArray[5] * rgbArray[3] / rgbArray[4];
            rgbMat[1, 1] = rgbArray[5];
            rgbMat[2, 1] = rgbArray[5] * (1 - rgbArray[3] - rgbArray[4]) / rgbArray[4];
            rgbMat[0, 2] = rgbArray[8] * rgbArray[6] / rgbArray[7];
            rgbMat[1, 2] = rgbArray[8];
            rgbMat[2, 2] = rgbArray[8] * (1 - rgbArray[6] - rgbArray[7]) / rgbArray[7];

            rgbTargetMat[0, 0] = rgbTargetArray[2] * rgbTargetArray[0] / rgbTargetArray[1];
            rgbTargetMat[1, 0] = rgbTargetArray[2];
            rgbTargetMat[2, 0] = rgbTargetArray[2] * (1 - rgbTargetArray[0] - rgbTargetArray[1]) / rgbTargetArray[1];
            rgbTargetMat[0, 1] = rgbTargetArray[5] * rgbTargetArray[3] / rgbTargetArray[4];
            rgbTargetMat[1, 1] = rgbTargetArray[5];
            rgbTargetMat[2, 1] = rgbTargetArray[5] * (1 - rgbTargetArray[3] - rgbTargetArray[4]) / rgbTargetArray[4];
            rgbTargetMat[0, 2] = rgbTargetArray[8] * rgbTargetArray[6] / rgbTargetArray[7];
            rgbTargetMat[1, 2] = rgbTargetArray[8];
            rgbTargetMat[2, 2] = rgbTargetArray[8] * (1 - rgbTargetArray[6] - rgbTargetArray[7]) / rgbTargetArray[7];

            Matrix<double> ccMat = rgbMat.Solve(rgbTargetMat);

            double[] result = new double[9];
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    result[i * 3 + j] = ccMat[i, j];
                }
            }

            return result;
        }

        private void btnCalColorGamut_Click(object sender, EventArgs e)
        {
            //// 收集必要数据
            //double rcx, rcy, gcx, gcy, bcx, bcy, wcx, wcy;
            //int rY, bY, gY, wY;

            //// 当前色域rgbw的色坐标值
            //rcx = rcy = gcx = gcy = bcx = bcy = wcx = wcy = -1d; //初始化为负数
            //double.TryParse(tbRedCx.Text, out rcx);
            //double.TryParse(tbRedCy.Text, out rcy);
            //double.TryParse(tbGreenCx.Text, out gcx);
            //double.TryParse(tbGreenCy.Text, out gcy);
            //double.TryParse(tbBlueCx.Text, out bcx);
            //double.TryParse(tbBlueCy.Text, out bcy);
            //double.TryParse(tbWhiteCx.Text, out wcx);
            //double.TryParse(tbWhiteCy.Text, out wcy);

            //if (rcx < 0 || rcx > 1 || gcx < 0 || gcx > 1 || bcx < 0 || bcx > 1 || wcx < 0 || wcx > 1 
            //    || rcy < 0 || rcy > 1 || gcy < 0 || gcy > 1 || bcy < 0 || bcy > 1 || wcy < 0 || wcy > 1)
            //{
            //    MessageBox.Show("色坐标数值错误, 取值范围应为[0,1]");
            //    return;
            //}

            //// 当前色域rgbw亮度
            //rY = gY = bY= wY = -1;
            //int.TryParse(tbRedL.Text, out rY);
            //int.TryParse(tbGreenL.Text, out gY);
            //int.TryParse(tbBlueL.Text, out bY);
            //int.TryParse(tbWhiteL.Text, out wY);
            //if (rY <= 0 || gY <= 0 || bY <= 0 || wY <= 0)
            //{
            //    MessageBox.Show("亮度数值错误，应大于0");
            //    return;
            //}

            //// 目标色域RGBW色坐标
            //double trcx, trcy, tgcx, tgcy, tbcx, tbcy, twcx, twcy;

            //trcx = trcy = tgcx = tgcy = tbcx = tbcy = twcx = twcy = -1;
            //double.TryParse(tbTargetRedCx.Text, out trcx);
            //double.TryParse(tbTargetRedCy.Text, out trcy);
            //double.TryParse(tbTargetGreenCx.Text, out tgcx);
            //double.TryParse(tbTargetGreenCy.Text, out tgcy);
            //double.TryParse(tbTargetBlueCx.Text, out tbcx);
            //double.TryParse(tbTargetBlueCy.Text, out tbcy);
            //double.TryParse(tbTargetWhiteCx.Text, out twcx);
            //double.TryParse(tbTargetWhiteCy.Text, out twcy);

            //// 目标色域亮度
            //double twY;

            //twY = (int)(wY * 0.8);

            //// RGB坐标和亮度
            //double[] rgbArray = new double[9];
            //rgbArray[0] = rcx;
            //rgbArray[1] = rcy;
            //rgbArray[2] = rY;
            //rgbArray[3] = gcx;
            //rgbArray[4] = gcy;
            //rgbArray[5] = gY;
            //rgbArray[6] = bcx;
            //rgbArray[7] = bcy;
            //rgbArray[8] = bY;

            //// W坐标和亮度
            //double[] wArray = new double[3];
            //wArray[0] = wcx; 
            //wArray[1] = wcy;
            //wArray[2] = wY;

            // // 目标W坐标和亮度
            //double[] tArray = new double[3];
            //tArray[0] = twcx;
            //tArray[1] = twcy;
            //tArray[2] = twY;

            //// 先做一次色温变换
            //double[] target_result = getRGBPrefix(rgbArray, tArray);


            //double[] rgbTargetArray = new double[9];
            //rgbTargetArray[0] = trcx;
            //rgbTargetArray[1] = trcy;
            //rgbTargetArray[2] = 0;
            //rgbTargetArray[3] = tgcx;
            //rgbTargetArray[4] = tgcx;
            //rgbTargetArray[5] = 0;
            //rgbTargetArray[6] = tbcx;
            //rgbTargetArray[7] = tbcx;
            //rgbTargetArray[8] = 0;

            //int[] target_L = getRGBBrightness(rgbTargetArray, wArray, ori_result);

            //rgbTargetArray[2] = target_L[0];
            //rgbTargetArray[5] = target_L[1];
            //rgbTargetArray[8] = target_L[2];

            //tbTargetRedL.Text = target_L[0].ToString();
            //tbTargetGreenL.Text = target_L[1].ToString();
            //tbTargetBlueL.Text = target_L[2].ToString();
            //tbTargetWhiteL.Text = twY.ToString();

            //rgbResult = getColorGamut(rgbArray, rgbTargetArray);

            //Caculated = true;
            //cvtMode = 2;
        }

        private void cbDefaultGaumt_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbDefaultGaumt.SelectedIndex == 0)
            {
                tbTargetRedCx.Enabled = true;
                tbTargetRedCy.Enabled = true;
                tbTargetGreenCx.Enabled = true;
                tbTargetGreenCy.Enabled = true;
                tbTargetBlueCx.Enabled = true;
                tbTargetBlueCy.Enabled = true;
                tbTargetWhiteCx.Enabled = true;
                tbTargetWhiteCy.Enabled = true;
            }
            else
            {
                tbTargetRedCx.Enabled = false;
                tbTargetRedCy.Enabled = false;
                tbTargetGreenCx.Enabled = false;
                tbTargetGreenCy.Enabled = false;
                tbTargetBlueCx.Enabled = false;
                tbTargetBlueCy.Enabled = false;
                tbTargetWhiteCx.Enabled = false;
                tbTargetWhiteCy.Enabled = false;

                tbTargetRedCx.Text = ColorGamut[cbDefaultGaumt.Text][1];
                tbTargetRedCy.Text = ColorGamut[cbDefaultGaumt.Text][2];
                tbTargetGreenCx.Text = ColorGamut[cbDefaultGaumt.Text][3];
                tbTargetGreenCy.Text = ColorGamut[cbDefaultGaumt.Text][4];
                tbTargetBlueCx.Text = ColorGamut[cbDefaultGaumt.Text][5];
                tbTargetBlueCy.Text = ColorGamut[cbDefaultGaumt.Text][6];
                tbTargetWhiteCx.Text = ColorGamut[cbDefaultGaumt.Text][7];
                tbTargetWhiteCy.Text = ColorGamut[cbDefaultGaumt.Text][8];
            }
        }

        // 设置配置参数
        private void setCfgState(byte[] dataBuff, int dataLength, byte startaddr)
        {
            // 获取解码器控制权
            baseCoreNet.setControlState(subIndex, true, false);
            Thread.Sleep(100);

            // 写入调整数据
            byte[] tempdata = new byte[dataLength];
            for (int i = 0; i < dataLength; i += dataLength)
            {
                for (int k = 0; k < dataLength; k++)
                {
                    tempdata[k] = dataBuff[i + k];
                }
                baseCoreNet.setMcuConfig(subIndex, portIndex, miniIndex, i + startaddr, tempdata, dataLength);
                Thread.Sleep(100);
            }

            // 设置工作模式
            baseCoreNet.setMcuActive(subIndex, portIndex, miniIndex);
            Thread.Sleep(100);

            // 解除解码器控制权
            baseCoreNet.setControlState(subIndex, false, false);
            Thread.Sleep(100);
        }

        



    }
}
